S05-10 高级特性-Lombok
[TOC]
Lombok
Lombok 是 Java 开发中非常流行的一个工具库。它的核心作用是通过注解(Annotations) 来自动生成 Java 中的“样板代码(Boilerplate Code)”,例如 getter、setter、构造函数、toString() 等,从而极大地简化代码,让开发者专注于核心业务逻辑。
Lombok 的工作原理
Lombok 的工作原理:
很多人担心 Lombok 会影响程序运行时的性能,但实际上它完全没有运行时开销。
Lombok 的工作发生在编译阶段(基于 JSR 269: Pluggable Annotation Processing API)。当 Java 编译器(如 javac)将 .java 源码编译为 .class 字节码时,Lombok 会介入并修改抽象语法树(AST),将需要生成的代码直接注入到最终的字节码文件中。因此,在 JVM 运行时,带有 Lombok 注解的类和手写了所有方法的类是没有任何区别的。
基础示例
Lombok 能帮你立刻省去那些繁琐的面向对象“样板代码”(比如构造方法、封装用的 Getter/Setter)。
我们就用最经典的 封装(Encapsulation) 和 对象创建(构造方法) 来做一个入门案例。
案例背景:定义一个“学生”JavaBean类:
在学习面向对象时,老师一定会教你:属性要私有化(private),并对外提供公共的访问方法(public get/set)。
第一步:编写 Student 类(使用 Lombok):
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
// Lombok 会在编译时自动帮我们写好很多代码
@Data // 自动生成所有 private 属性的 Getter/Setter 方法,以及 toString() 方法
@NoArgsConstructor // 自动生成一个“无参数”的构造方法
@AllArgsConstructor // 自动生成一个包含“所有参数”的构造方法
public class Student {
// 对象的属性(私有化,符合面向对象的封装特性)
private String name;
private int age;
private String studentId;
// 注意:这里里面什么都不用写!不需要手敲 get/set 和构造方法。
}通过这个案例,你可以把刚学的 OOP(面向对象编程)知识和 Lombok 对应起来:
封装:你只需关注定义
private String name;,Lombok 的@Data替你完成了开放public String getName()的体力活。构造方法重载:你不需要手写多个构造方法,
@NoArgsConstructor和@AllArgsConstructor让你既能new Student(),也能new Student("小红", 19, "S1002")。注意事项:要在你的电脑上真正跑通这段代码,除了引入 Lombok 的代码库,你的开发工具(比如 IntelliJ IDEA 或 Eclipse)必须安装 Lombok 插件,否则代码里的
setName()和getName()会标红报错,因为编辑器默认“看”不到 Lombok 生成的方法。

第二步:编写 Main 测试类:
在这个测试类里,我们要去使用刚才 Lombok 帮我们偷偷生成的那些方法。
public class Main {
public static void main(String[] args) {
// --- 演示 1:使用无参构造方法 & Setter 赋值 ---
// 这里的无参构造方法是 @NoArgsConstructor 帮我们生成的
Student student1 = new Student();
// 这里的 set 方法是 @Data 帮我们生成的
student1.setName("小明");
student1.setAge(18);
student1.setStudentId("S1001");
// 这里的 get 方法也是 @Data 帮我们生成的
System.out.println("学生1的姓名是:" + student1.getName());
// --- 演示 2:使用全参构造方法快速创建对象 ---
// 这里的全参构造方法是 @AllArgsConstructor 帮我们生成的
Student student2 = new Student("小红", 19, "S1002");
// --- 演示 3:打印对象信息 ---
// 通常直接打印对象,输出的会是内存地址(如 Student@1b6d3586)
// 但因为使用了 @Data,它帮我们重写了 toString() 方法,所以打印出来的是清晰的数据内容
System.out.println("学生1详细信息:" + student1);
System.out.println("学生2详细信息:" + student2);
}
}第三步:运行结果:
如果你运行上面的 Main 类,控制台会输出:
学生1的姓名是:小明
学生1详细信息:Student(name=小明, age=18, studentId=S1001)
学生2详细信息:Student(name=小红, age=19, studentId=S1002)核心注解详解
基础属性注入
基础属性注入:
@Getter/@Setter- 作用:自动为类中的所有非静态字段生成
get和set方法。如果标注在类上,则作用于所有字段;标注在特定字段上,则只对该字段生效。 - 附加配置:可以通过
AccessLevel控制访问权限,例如@Getter(AccessLevel.PROTECTED)。
- 作用:自动为类中的所有非静态字段生成
@ToString- 作用:自动生成
toString()方法。 - 注意:可以通过
exclude参数排除某些字段,或者用of指定只包含哪些字段(避免循环引用时引起栈溢出)。
- 作用:自动生成
@EqualsAndHashCode- 作用:自动生成
equals()和hashCode()方法。默认使用所有非静态、非瞬态(transient)字段。
- 作用:自动生成
构造函数生成
构造函数生成:
@NoArgsConstructor:生成一个无参构造函数。@AllArgsConstructor:生成一个包含类中所有字段的全参构造函数。@RequiredArgsConstructor:生成一个包含所有带有final修饰符和@NonNull注解的字段的构造函数。
组合与高级注解
组合与高级注解:
@Data(最常用)- 作用:这是一个复合注解,等同于同时使用了
@Getter、@Setter、@RequiredArgsConstructor、@ToString和@EqualsAndHashCode。 - 场景:通常用于普通的 POJO(Plain Old Java Object)、DTO、VO 类。
- 作用:这是一个复合注解,等同于同时使用了
@Value- 作用:相当于不可变(Immutable)版本的
@Data。它会将所有字段默认变为private final,并且只生成 Getter,不生成 Setter。
- 作用:相当于不可变(Immutable)版本的
@Builder作用:自动为类生成建造者模式(Builder Pattern) 的代码,使得对象的链式创建变得非常优雅。
示例:
javaUser user = User.builder().name("张三").age(25).build();
日志注解
日志注解:
@Slf4j/@Log等- 作用:自动在类中注入一个静态的日志对象。
@Slf4j会自动生成private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(YourClass.class);。 - 场景:极大地简化了打印日志的准备工作,直接在代码中调用
log.info("...")即可。
- 作用:自动在类中注入一个静态的日志对象。
传统代码与 Lombok 代码对比
传统代码与 Lombok 代码对比:
未使用 Lombok 的传统 Java 类:
public class User {
private String name;
private int age;
public User() {}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
// 还需要手写 equals 和 hashCode 方法...
}使用 Lombok 后:
import lombok.Data;
@Data
public class User {
private String name;
private int age;
}Lombok 的优缺点分析
优点:
代码极度简洁:去除了大量冗余代码,类结构一目了然,只保留核心属性。
提高开发效率:修改字段时(如修改字段名、增删字段),不需要手动去修改对应的 getter、setter 和构造函数。
零运行时开销:由于是编译时生成,不影响程序运行性能。
缺点与争议:
环境依赖:不仅需要在项目中引入依赖,团队中所有开发者的 IDE(如 IDEA, Eclipse)都必须安装 Lombok 插件,否则代码会大面积报错(找不到 get/set 方法)。
降低可读性与调试难度:因为方法是隐式的,有时你很难一眼看出一个类的
hashCode是基于哪些字段生成的。滥用带来的坑:
- 循环引用:在 JPA/Hibernate 等 ORM 框架中,如果双向关联的实体类都使用了
@Data(包含了@ToString和@EqualsAndHashCode),在打印日志或比对时会引发StackOverflowError。 - 继承问题:子类使用
@Data或@EqualsAndHashCode时,默认不会调用父类的equals方法(除非显式配置callSuper = true),这可能导致对象比较出现意料之外的结果。
- 循环引用:在 JPA/Hibernate 等 ORM 框架中,如果双向关联的实体类都使用了
最佳实践建议
最佳实践建议:
- POJO 类推荐:在普通的 DTO、VO、Param 类中大胆使用
@Data和@Builder。 - ORM 实体类慎用:在 JPA Entity 中,尽量避免使用
@Data,推荐只使用@Getter、@Setter和@ToString(exclude="关联字段"),以防止懒加载失效和循环引用问题。 - 使用
@Slf4j:取代手动声明 Logger 的繁琐过程。